package org.dromara.system.service.impl.trading;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.dromara.common.core.domain.R;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.CreditCardRewardRecordsBo;
import org.dromara.system.domain.bo.SysUserPurseBo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.enums.MachineConstant;
import org.dromara.system.enums.NotificationEnum;
import org.dromara.system.enums.SysUserFreezePointsRecordsEnum;
import org.dromara.system.enums.SysUserPointsRecordsEnum;
import org.dromara.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 王星
 * @date 2024/5/31 下午3:21
 */
@Log4j2
public abstract class BaseTrading<T, W> {

    @Resource
    private ITradingRecordsService tradingRecordsService;
    @Autowired
    private ISysUserService sysUserService;
    @Resource
    private ISysUserTradingConfigService sysUserTradingConfigService;
    @Resource
    private ISysUserCommonConfigService sysUserCommonConfigService;
    @Resource
    private ISysUserPurseService sysUserPurseService;
    @Resource
    private ISysUserPointsRecordsService sysUserPointsRecordsService;
    @Resource
    private ISysUserFreezePointsRecordsService sysUserFreezePointsRecordsService;
    @Resource
    private ISysUserMachineService sysUserMachineService;
    @Resource
    private ICreditCardRewardRecordsService creditCardRewardRecordsService;
    @Resource
    private ISysUserLotteryPointsRecordsService sysUserLotteryPointsRecordsService;
    @Resource
    private IProductLineInformationService productLineInformationService;

    public R<TradingRecords> dealUserTrading(TradingRecords tradingRecords) {
        log.info("交易处理数据={}", JSONUtil.toJsonStr(tradingRecords));
        SysUserMachine sysUserMachine = sysUserMachineService.lambdaQuery().eq(SysUserMachine::getSn, tradingRecords.getSn()).one();
        if (ObjectUtil.isNull(sysUserMachine)) {
            return R.fail("机器不存在！");
        }
        Long count = tradingRecordsService.lambdaQuery()
            .eq(TradingRecords::getOrderNo, tradingRecords.getOrderNo())
            .eq(TradingRecords::getSn, tradingRecords.getSn()).count();
        if (count > 0) {
            return R.fail("该交易记录已存在！");
        }
        //插入交易记录
        tradingRecords.setUserId(sysUserMachine.getUserId());
        tradingRecords.setMachineId(sysUserMachine.getId());
        tradingRecordsService.save(tradingRecords);

        //借记卡不返现
        Boolean isDebitCard = tradingRecords.getIsDebitCard();
        if (ObjectUtil.isNotNull(isDebitCard) && isDebitCard) {
            R.ok(tradingRecords);
        }
        //计算返现
        if (ObjectUtil.isNotNull(sysUserMachine.getBindUserId())) {

            SysUserVo sysUserVo = sysUserService.selectUserById(sysUserMachine.getBindUserId());
            //处理一下每交易一万给商户一个抽奖积分
            BigDecimal add = NumberUtil.add(sysUserVo.getDealSumTag(), tradingRecords.getAmount());
            BigDecimal dealSumTag = BigDecimal.ZERO;
            if (NumberUtil.isLess(add, Convert.toBigDecimal(10000))) {
                dealSumTag = add;
            } else {
                // 计算整数部分
                BigDecimal quotient = NumberUtil.round(NumberUtil.div(add, Convert.toBigDecimal(10000)), 0, RoundingMode.DOWN);
                // 计算余数
                dealSumTag = add.remainder(Convert.toBigDecimal(10000));
                //增加抽奖积分
                SysUserPurseBo sysUserLotteryPurseBo = SysUserPurseBo.builder()
                    .userId(sysUserVo.getUserId())
                    .lotteryPoints(quotient)
                    .build();
                sysUserLotteryPointsRecordsService.updateUserLotteryPoints(CollUtil.newArrayList(sysUserLotteryPurseBo));
            }
            sysUserService.updateUserDealSumTag(sysUserMachine.getBindUserId(), dealSumTag);

            //查询一级是否设置返现需要VIP
            SysUserCommonConfig sysUserCommonConfig = sysUserCommonConfigService.lambdaQuery().eq(SysUserCommonConfig::getUserId, sysUserVo.getOneId()).one();
            Integer cashbackIsMember = Convert.toInt(sysUserCommonConfig.getCashBackIsMember(), MachineConstant.NUMBER.ZERO);
            if (ObjectUtil.equal(cashbackIsMember, MachineConstant.NUMBER.ONE)) {
                if (ObjectUtil.equal(sysUserVo.getMemberTag(), MachineConstant.NUMBER.ZERO)) {
                    return R.fail("商户没有开通VIP");
                }
            }
            //查询一级代理设置的返现配置
            List<SysUserTradingConfig> sysUserTradingConfigs = new ArrayList<>();
            if (ObjectUtil.equal(cashbackIsMember, MachineConstant.NUMBER.ONE)) {
                sysUserTradingConfigs = sysUserTradingConfigService.lambdaQuery()
                    .eq(SysUserTradingConfig::getUserId, sysUserVo.getOneId())
                    .eq(SysUserTradingConfig::getMemberConfigId, sysUserVo.getMemberTag())
                    .orderByDesc(SysUserTradingConfig::getMinAmount)
                    .list();
            } else {
                sysUserTradingConfigs = sysUserTradingConfigService.lambdaQuery()
                    .eq(SysUserTradingConfig::getUserId, sysUserVo.getOneId())
                    .isNull(SysUserTradingConfig::getMemberConfigId)
                    .orderByDesc(SysUserTradingConfig::getMinAmount)
                    .list();
            }
            SysUserTradingConfig sysUserTradingConfig = sysUserTradingConfigs.stream()
                .filter(t -> NumberUtil.isGreaterOrEqual(sysUserMachine.getDealSum(), t.getMinAmount())).findFirst().orElse(null);
            if (ObjectUtil.isNull(sysUserTradingConfig)) {
                return R.fail("未查询到匹配的配置！");
            }

            BigDecimal cashBackRate = sysUserTradingConfig.getCashBackRate();
            BigDecimal rewards = BigDecimal.ZERO;
            BigDecimal cashBack = Convert.toBigDecimal(NumberUtil.mul(tradingRecords.getAmount(), NumberUtil.div(cashBackRate, MachineConstant.NUMBER.TEN_THOUSAND)), BigDecimal.ZERO);
            rewards = NumberUtil.add(rewards, cashBack);
            SysUserPurse sysUserPurse = sysUserPurseService.lambdaQuery().eq(SysUserPurse::getUserId, sysUserMachine.getBindUserId()).one();
            rewards = NumberUtil.isLess(sysUserPurse.getFreezePoints(), rewards) ? sysUserPurse.getFreezePoints() : rewards;
            SysUserPurseBo sysUserPurseBoFrozen = SysUserPurseBo.builder()
                .userId(sysUserMachine.getBindUserId())
                .type(SysUserFreezePointsRecordsEnum.TRADING_DECREASE_POINTS.getCode())
                .freezePoints(NumberUtil.mul(rewards, MachineConstant.NUMBER.ONE_NEGATIVE))
                .tradingSnRemark(tradingRecords.getSn())
                .tradingAmountRemark(tradingRecords.getAmount())
                .build();
            sysUserFreezePointsRecordsService.updateUserFreezePoints(CollUtil.newArrayList(sysUserPurseBoFrozen));
            SysUserPurseBo sysUserPurseBo = SysUserPurseBo.builder()
                .userId(sysUserMachine.getBindUserId())
                .type(SysUserPointsRecordsEnum.TRADING_POINTS.getCode())
                .points(rewards)
                .tradingSnRemark(tradingRecords.getSn())
                .tradingAmountRemark(tradingRecords.getAmount())
                .build();
            sysUserPointsRecordsService.updateUserPoints(CollUtil.newArrayList(sysUserPurseBo));
            tradingRecordsService.lambdaUpdate()
                .set(TradingRecords::getPoints, rewards)
                .eq(TradingRecords::getId, tradingRecords.getId())
                .update();
            //增加刷卡奖励记录
            CreditCardRewardRecordsBo creditCardRewardRecordsBo = CreditCardRewardRecordsBo.builder()
                .machineId(sysUserMachine.getId())
                .sn(sysUserMachine.getSn())
                .orderNo(tradingRecords.getOrderNo())
                .cashBackPoints(rewards)
                .userId(sysUserMachine.getBindUserId())
                .build();
            creditCardRewardRecordsService.insertByBo(creditCardRewardRecordsBo);
        }
        sysUserMachine.setMerchantCode(StrUtil.isBlank(sysUserMachine.getMerchantCode())
            ? Convert.toStr(tradingRecords.getMerchantCode()) : sysUserMachine.getMerchantCode());
        sysUserMachine.setMerchantName(StrUtil.isBlank(sysUserMachine.getMerchantName())
            ? Convert.toStr(tradingRecords.getMerchantName()) : sysUserMachine.getMerchantName());
        sysUserMachine.setDealSum(NumberUtil.add(sysUserMachine.getDealSum(), tradingRecords.getAmount()));
        sysUserMachineService.updateById(sysUserMachine);
        return R.ok(tradingRecords);
    }

    public NotificationEnum getNotificationEnum() {
        throw new UnsupportedOperationException("unrealized");
    }


    public void updateMachineDepositAmt(String sn, BigDecimal depositAmt) {
        sysUserMachineService.lambdaUpdate()
            .set(SysUserMachine::getDeposit, depositAmt)
            .eq(SysUserMachine::getSn, sn).update();
    }

    public ProductLineInformation getBrandProductsLineById(Integer code) {
        return productLineInformationService.lambdaQuery()
            .eq(ProductLineInformation::getId, code)
            .one();
    }


}
